/***********************************************************************************
**  
* @copyright (c) 2010-2019,  Technology Co., LTD. All Right Reserved.
*
************************************************************************************/
/**
* @file	    duye_net_server.h
* @version     
* @brief      
* @author
* @date	    2013-03-31
* @note 
*
* 1. 2013-03-31 Created this file
*/

#pragma once

#include <string>
#include <map>
#include <duye_type.h>
#include <duye_lock.h>

namespace duye {

// transfer temp message buffer 1k
#define NET_MSG_BUF_SIZE 1024

/**
 * @brief network service status define
 */
typedef enum {
    // server uninit, when new object
    SERVER_UNINIT,
    // server had init, when call relation init function
    SERVER_INIT,
    // server is running, when after call startServer()
    SERVER_RUNNING,
    // server had stoped, when after call stopServer()
    SERVER_STOPED,
    // server exit, when delete object
    SERVER_EXIT
} ServerStatus;

/**
 * @brief network server parameters
 */
class NetServerPara {
public:
    NetServerPara() : port(0), maxConn(1024), isBlock(true), recvBufSize(2048) {}
    
	// local interface device name, default is generated by system
	std::string localDevName;
	// bind server address, default is for all net device
	std::string bindAddr;
	// bind local port, default is generated by system, server peer need setting this parameter
	uint16 port;
    // max count of support client connection, default is 1024
    uint32 maxConn;
    // open socket is block/unblock, default is block
    bool isBlock;
	// received data buffer max size
	uint32 recvBufSize;
};

/**
 * @brief network server abstract class
 */
class NetServer {
public:
    NetServer() : m_status(SERVER_UNINIT) {}
    explicit NetServer(const char* serverName) : m_serverName(serverName), m_status(SERVER_UNINIT) {}
    virtual ~NetServer() { setServerStatus(SERVER_EXIT); }

    /**
     * @brief start network server
     * @return true/false
     */
    virtual bool startServer() = 0;
    /**
     * @brief stop network server
     * @return true/false
     */
    virtual bool stopServer() = 0;

    /**
     * @brief set server name
     * @para [in] serverName : server name
     */
    void setServerName(const std::string& serverNane) { m_serverName = serverNane; }
    /**
     * @brief get server name
     * @return server name
     */
    const std::string& serverName() { return m_serverName; }

    /**
     * @brief set server status
     * @para [in] status : server status
     */
    void setServerStatus(const ServerStatus status) { m_status = status; }
    /**
     * @brief get server status
     * @return server status
     */
    ServerStatus serverStatus() { return m_status; }
    
private:
    // server name
    std::string     m_serverName;
    // server status
    ServerStatus    m_status;
};

/**
 * @brief net client proxy template
 */
template<typename T>
class ClientProxy : public T {
public:
    // <sockfd, T*>
    typedef std::map<int32, T*> ProxyMap;
        
public:
    ClientProxy() {}
    virtual ~ClientProxy() {}

protected:
	bool addProxy(const int32 clientSockfd, T* t);
    T* proxy(const int32 clientSockfd);
	bool delProxy(const int32 clientSockfd);
	bool cleanProxy();
    
private:
    ProxyMap    m_proxyMap;
    Mutex       m_proxyMapMutex;
};

template<typename T>
bool ClientProxy<T>::addProxy(const int32 clientSockfd, T* t)
{
    delProxy(clientSockfd);
	AutoLock autoLock(m_proxyMapMutex);
	m_proxyMap.insert(std::make_pair(clientSockfd, t));
	return true;
}

template<typename T>
T* ClientProxy<T>::proxy(const int32 clientSockfd)
{
 	AutoLock autoLock(m_proxyMapMutex);
	typename ProxyMap::iterator iter = m_proxyMap.find(clientSockfd);
	if (iter == m_proxyMap.end())
	{
		return NULL;
	}   

    return iter->second;
}

template<typename T>
bool ClientProxy<T>::delProxy(const int32 clientSockfd)
{
	AutoLock autoLock(m_proxyMapMutex);
	typename ProxyMap::iterator iter = m_proxyMap.find(clientSockfd);
	if (iter == m_proxyMap.end())
	{
		return false;
	}

	if (iter->second)
		delete iter->second;
	
	m_proxyMap.erase(iter);
	
	return true;
}

template<typename T>
bool ClientProxy<T>::cleanProxy()
{
	AutoLock autoLock(m_proxyMapMutex);
    typename ProxyMap::iterator iter = m_proxyMap.begin();
    for (; iter != m_proxyMap.end(); ++iter)
    {
        if (iter->second)
        {
            delete iter->second;
            iter->second = NULL;
        }
    }    

	return true;
}

}
